#include <math.h>
#include <string.h>
#include <stdio.h>
#include <stm32f10x_rcc.h>
#include <stm32f10x_dac.h>
#include <stm32f10x_gpio.h>
#include <stm32f10x_tim.h>
#include <Config.h>
#include <DAC_STM32.h>

#define dac_buff_size 2048
static uint16_t dac_buff[dac_buff_size];
static unsigned int pos_buff = 0;
static unsigned int time_scale = 0;
static unsigned int time_scale_tmp = 0;
static unsigned int count_buff_element = 0;

void DAC1_Configuration(void) {
	DAC_InitTypeDef DAC_InitStructure;
	GPIO_InitTypeDef GPIO_InitStructure;

	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_AFIO, ENABLE);
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_DAC, ENABLE);

	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIO_InitStructure);

	DAC_InitStructure.DAC_Trigger = DAC_Trigger_None;
	DAC_InitStructure.DAC_WaveGeneration = DAC_Wave_Triangle;
	DAC_InitStructure.DAC_LFSRUnmask_TriangleAmplitude
			= DAC_TriangleAmplitude_4095;
	DAC_InitStructure.DAC_OutputBuffer = DAC_OutputBuffer_Disable;
	DAC_Init(DAC_Channel_1, &DAC_InitStructure);
	DAC_Cmd(DAC_Channel_1, ENABLE);
}

void DAC1_Out(uint16_t value) {
	DAC_SetChannel1Data(DAC_Align_12b_R, value);
}

void DAC1_generate_const(unsigned int level) {
	Switch_timer_DAC_IRQ(DISABLE);
	if (level > 100) {
		OUTPUT_USARTTerm;
		puts(
				"out of level, auto set level of DAC output to 100 percent of VDD\r\n");
		DAC1_Out(4095);
	} else {
		DAC1_Out(level * 4095 / 100);
	}
}

void DAC1_generate_sine(unsigned int freq) {
	unsigned int pos;
	unsigned long T = 1 * 1000000 / freq; //T in micro sec
	Switch_timer_DAC_IRQ(DISABLE);
	if (T <= dac_buff_size) {
		time_scale = 1;
		count_buff_element = T;
		for (pos = 0; pos < T; pos++) {
			dac_buff[pos] = (unsigned int) (2047 + 2047 * sin((pi * (double) (2
					* freq * pos)) / 1000000));
		}
	} else {
		double scale = ((double) T / dac_buff_size);
		for (pos = 0; pos < dac_buff_size; pos++) {
			dac_buff[pos] = (unsigned int) (2047 + 2047 * sin((pi * (double) (2
					* freq * pos * scale)) / 1000000));
		}
		time_scale = (unsigned int) scale;
		count_buff_element = dac_buff_size;
	}
	timer_DAC_config(time_scale);
	pos_buff = 0;
	time_scale_tmp = 0;
	Switch_timer_DAC_IRQ(ENABLE);
}

void DAC1_generate_square(unsigned int freq) {
	unsigned int pos;
	unsigned long T = 1 * 1000000 / freq; //T in micro sec
	Switch_timer_DAC_IRQ(DISABLE);
	if (T <= dac_buff_size) {
		time_scale = 1;
		count_buff_element = T;
		for (pos = 0; pos < T; pos++) {
			if (pos * 2 < T) {
				dac_buff[pos] = 4095;
			} else {
				dac_buff[pos] = 0;
			}
		}
	} else {
		double scale = ((double) T / dac_buff_size);
		for (pos = 0; pos < dac_buff_size; pos++) {
			if (pos * 2 < dac_buff_size) {
				dac_buff[pos] = 4095;
			} else {
				dac_buff[pos] = 0;
			}
		}
		time_scale = (unsigned int) scale;
		count_buff_element = dac_buff_size;
	}
	timer_DAC_config(time_scale);
	pos_buff = 0;
	time_scale_tmp = 0;
	Switch_timer_DAC_IRQ(ENABLE);
}
void DAC1_generate_triangular(unsigned int freq) {
	unsigned int pos;
	unsigned long T = 1 * 1000000 / freq; //T in micro sec
	Switch_timer_DAC_IRQ(DISABLE);
	if (T <= dac_buff_size) {
		time_scale = 1;
		count_buff_element = T;
		for (pos = 0; pos < T; pos++) {
			if (pos * 2 < T) {
				dac_buff[pos] = 4095 * pos * 2 / T;
			} else {
				dac_buff[pos] = 4095 * 2 - 4095 * pos * 2 / T;
			}
		}
	} else {
		double scale = ((double) T / dac_buff_size);
		for (pos = 0; pos < dac_buff_size; pos++) {
			if (pos * 2 < dac_buff_size) {
				dac_buff[pos] = 4095 * pos * 2 / dac_buff_size;
			} else {
				dac_buff[pos] = 4095 * 2 - 4095 * pos * 2 / dac_buff_size;
			}
		}
		time_scale = (unsigned int) scale;
		count_buff_element = dac_buff_size;
	}
	timer_DAC_config(time_scale);
	pos_buff = 0;
	time_scale_tmp = 0;
	Switch_timer_DAC_IRQ(ENABLE);
}
void DAC1_generate_squarecustom(unsigned int Ton, unsigned int Toff) {
	unsigned int pos;
	unsigned long T = (Ton + Toff) * 1000;
	Switch_timer_DAC_IRQ(DISABLE);
	if (T <= dac_buff_size) {
		time_scale = 1;
		count_buff_element = T;
		for (pos = 0; pos < T; pos++) {
			if (pos < Ton) {
				dac_buff[pos] = 4095;
			} else {
				dac_buff[pos] = 0;
			}
		}
	} else {
		double scale = ((double) T / dac_buff_size);
		unsigned int Pos_revert = (Ton * 1000 * dac_buff_size) / T;
		for (pos = 0; pos < dac_buff_size; pos++) {
			if (pos < Pos_revert) {
				dac_buff[pos] = 4095;
			} else {
				dac_buff[pos] = 0;
			}
		}
		time_scale = (unsigned int) scale;
		count_buff_element = dac_buff_size;
	}
	timer_DAC_config(time_scale);
	pos_buff = 0;
	time_scale_tmp = 0;
	Switch_timer_DAC_IRQ(ENABLE);
}

/*
 * ************************************************************
 * below is IRQhandler functions
 * ************************************************************
 */
void TIM4_IRQHandler(void) {
	if (TIM_GetITStatus(TIM4, TIM_IT_Update) == SET) {
			DAC_SetChannel1Data(DAC_Align_12b_R, dac_buff[pos_buff++]);
			if (pos_buff >= count_buff_element) {
				pos_buff = 0;
			}
		TIM_ClearITPendingBit(TIM4, TIM_IT_Update);
	}
}
